package proxy

import (
	"go-proxy/common"
	"go-proxy/config"
	"go-proxy/proxy/router"
	"net/http"
	"strings"
	"sync"
)

var (
	serviceRouteMap  = make(map[string]string)
	serviceRouteLock sync.RWMutex

	routerProxyMap  = make(map[string]string)
	routerProxyLock sync.RWMutex

	routeMap  = make(map[string]*config.Route)
	routeLock sync.RWMutex
)

func InitRouter() {
	routes := config.ProxyConfigData.Routes
	for _, route := range routes {
		for _, proxyName := range route.TargetProxy {
			SetRouterProxy(proxyName, route.Name)
		}
		SetServiceRoute(route.TargetService, route.Name)
		SetRouter(route.Name, &route)
	}
}

func SetRouter(name string, route *config.Route) {
	routeLock.Lock()
	defer routeLock.Unlock()
	routeMap[name] = route
}

func GetRoute(name string) *config.Route {
	routeLock.RLock()
	defer routeLock.RUnlock()
	return routeMap[name]
}

func SetServiceRoute(serviceName string, routeName string) {
	serviceRouteLock.Lock()
	defer serviceRouteLock.Unlock()
	routeNames := serviceRouteMap[serviceName]

	if len(routeNames) <= 0 {
		routeNames = routeName
		serviceRouteMap[serviceName] = routeNames
		return
	}

	if strings.Contains(routeNames, routeName) {
		return
	} else {
		routeNames += "," + routeName
	}
	serviceRouteMap[serviceName] = routeNames
}

func GetServiceRoute(serviceName string) string {
	serviceRouteLock.RLock()
	defer serviceRouteLock.RUnlock()
	return serviceRouteMap[serviceName]
}

func SetRouterProxy(proxyName string, routeName string) {
	routerProxyLock.Lock()
	defer routerProxyLock.Unlock()
	routeNames := routerProxyMap[proxyName]

	if len(routeNames) <= 0 {
		routeNames = routeName
		routerProxyMap[proxyName] = routeNames
		return
	}

	if strings.Contains(routeNames, routeName) {
		return
	} else {
		routeNames += "," + routeName
	}
	routerProxyMap[proxyName] = routeNames
}

func GetRouterProxy(proxyName string) string {
	routerProxyLock.RLock()
	defer routerProxyLock.RUnlock()
	return routerProxyMap[proxyName]
}

func getRoutesByProxyName(proxyName string) []*config.Route {
	list := make([]*config.Route, 0)
	routeNames := GetRouterProxy(proxyName)
	if routeNames == "" || len(routeNames) <= 0 {
		return list
	}

	routes := strings.Split(routeNames, ",")
	for _, item := range routes {
		route := GetRoute(item)
		list = append(list, route)
	}
	return list
}

func matchRoute(proxyName string, r *http.Request) (*config.Route, bool) {
	routes := getRoutesByProxyName(proxyName)
	if len(routes) <= 0 {
		return nil, false
	}

	for _, route := range routes {
		common.LogDebug("matchRoute route:", route)
		if router.Match(route.PathType, route, r) {
			return route, true
		}
	}
	return nil, false
}
